<?php

namespace DreamCat\FrameCore\Cases;

use DreamCat\FrameCore\FpmEntrance;
use DreamCat\FrameCore\HelperClass\Bean\DemoBeanAlias;
use DreamCat\FrameCore\HelperClass\Controller\FlowController;
use DreamCat\FrameCore\HelperClass\TestEmit;
use DreamCat\FrameCore\HelperClass\Vo\DemoVo;
use DreamCat\FrameCore\ServerMessage\Response\JsonExResponse;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Zend\Diactoros\Response\TextResponse;
use Zend\HttpHandlerRunner\Emitter\EmitterInterface;

/**
 * 完整流程测试
 * @author vijay
 */
class FullFlowTest extends TestCase
{
    /** @var array 测试用的配置文件 */
    private static $config = [
        "router" => [
            "prefix" => "/api",
            "uris" => [
                "/test" => FlowController::class,
                "/testraw/{raw}" => FlowController::class . "::raw",
                "/test/noAct" => FlowController::class . "::noAct",
                "/errorCtl" => DemoVo::class,
            ],
        ],
        "db" => ["name" => "mydb"],
        "beans" => [
            EmitterInterface::class => TestEmit::class,
            DemoBeanAlias::class => [
                "alias" => ["alias"],
                "props" => ["id" => "bbc"],
            ],
        ],
        "http" => [
            "notFoundCode" => 406,
            "notFoundMsg" => "custom not found",
            "notAllowedCode" => 407,
            "notAllowedMsg" => "custom not allowed",
        ],
    ];
    /** @var string 项目根目录 */
    private static $rootPath;

    /**
     * 测试前的基境建设
     * @return void
     */
    public static function setUpBeforeClass(): void
    {
        parent::setUpBeforeClass();
        self::$rootPath = realpath(__DIR__ . "/../../..");
        if (!is_dir(self::$rootPath . "/cache/configs/")) {
            mkdir(self::$rootPath . "/cache/configs/", 0777, true);
        }
        $configPath = self::$rootPath . "/cache/configs/config.php";
        if (file_exists($configPath)) {
            rename($configPath, $configPath . ".bak");
        }
        file_put_contents($configPath, "<?php\nreturn " . var_export(self::$config, true) . ";");
    }

    /**
     * 测试完成的环境恢复
     * @return void
     */
    public static function tearDownAfterClass(): void
    {
        parent::tearDownAfterClass();
        $configPath = self::$rootPath . "/cache/configs/config.php";
        if (file_exists($configPath . ".bak")) {
            rename($configPath . ".bak", $configPath);
        } else {
            unlink($configPath);
        }
    }

    /**
     * 测试主流程
     * @param array $global 要调整的全局变量
     * @param ResponseInterface $expectOutput 预期的输出
     * @return void
     * @dataProvider normalData
     */
    public function testNormal(array $global, ResponseInterface $expectOutput)
    {
        # 生成全局变量
        $modified = [];
        if (isset($global["s"])) {
            $modified["s"] = $_SERVER;
        }
        foreach ($global["s"] ?? [] as $key => $value) {
            $_SERVER[$key] = $value;
        }
        if (isset($global["g"])) {
            $modified["g"] = $_GET;
        }
        foreach ($global["p"] ?? [] as $key => $value) {
            $_GET[$key] = $value;
        }
        if (isset($global["p"])) {
            $modified["p"] = $_POST;
        }
        foreach ($global["p"] ?? [] as $key => $value) {
            $_POST[$key] = $value;
        }
        # 调用启用入口
        chdir(self::$rootPath);
        FpmEntrance::start();

        # 恢复全局变量
        if (isset($modified["s"])) {
            $_SERVER = $modified["s"];
        }
        if (isset($modified["p"])) {
            $_POST = $modified["p"];
        }
        if (isset($modified["g"])) {
            $_GET = $modified["g"];
        }

        # 对比数据
        /** @var ResponseInterface $response */
        $response = TestEmit::$lastResponse;

        self::assertEquals(get_class($expectOutput), get_class($response), "返回值类型不一");
        self::assertEquals($expectOutput->getStatusCode(), $response->getStatusCode(), "状态码不正确");
        self::assertEquals($expectOutput->getBody()->getContents(), $response->getBody()->getContents(), "返回文本不正确");
    }

    /**
     * 常规流程测试用例
     * @return array
     */
    public function normalData()
    {
        return [
            [
                ["s" => ["REQUEST_URI" => "/api/test"]],
                new JsonExResponse(realpath(__DIR__ . "/../../../") . "::mydb/root"),
            ],
            [
                ["s" => ["REQUEST_URI" => "/api/ntest"]],
                new TextResponse("custom not found", 406),
            ],
            [
                [
                    "s" => [
                        "REQUEST_METHOD" => "POST",
                        "REQUEST_URI" => "/api/test",
                    ],
                ],
                new TextResponse("custom not allowed", 407),
            ],
            [
                [
                    "s" => ["REQUEST_URI" => "/api/errorCtl"],
                ],
                new TextResponse("", 500),
            ],
            [
                [
                    "s" => ["REQUEST_URI" => "/api/testraw/003"],
                ],
                new TextResponse("003::bbc", 302),
            ],
            [
                [
                    "s" => ["REQUEST_URI" => "/api/test/noAct"],
                ],
                new TextResponse("", 500),
            ],
        ];
    }
}

# end of file
